home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-04-15 | 50.1 KB | 1,329 lines |
- Path: bloom-beacon.mit.edu!hookup!swrinde!cs.utexas.edu!howland.reston.ans.net!europa.eng.gtefsd.com!news.umbc.edu!cs.umd.edu!kong.gsfc.nasa.gov!kong.gsfc.nasa.gov!not-for-mail
- From: dealy@kong.gsfc.nasa.gov (Brian Dealy)
- Newsgroups: comp.windows.x.motif,news.answers,comp.answers
- Subject: Motif FAQ (Part 3 of 5)
- Followup-To: poster
- Date: 14 Apr 1994 15:20:35 -0400
- Organization: NASA/Goddard Space Flight Center
- Lines: 1311
- Approved: news-answers-request@MIT.Edu
- Distribution: inet
- Expires: +1 months
- Message-ID: <2ok523$5em@kong.gsfc.nasa.gov>
- Reply-To: dealy@kong.gsfc.nasa.gov (Brian Dealy)
- NNTP-Posting-Host: kong.gsfc.nasa.gov
- Keywords: FAQ question answer
- Xref: bloom-beacon.mit.edu comp.windows.x.motif:15727 news.answers:18059 comp.answers:4910
-
- Archive-name: motif-faq/part3
- Last-modified: APR 04, 1994
- Version: 3.6
-
-
-
-
-
-
-
- -----------------------------------------------------------------------------
- Subject: 62) TOPIC: FORM WIDGET
-
-
- -----------------------------------------------------------------------------
- Subject: 63) Why don't labels in a Form resize when the label is changed?
- I've got some labels in a form. The labels don't resize whenever the label
- string resource is changed. As a result, the operator has to resize the window
- to see the new label contents. I am using Motif 1.1.
-
- Answer: This problem may happen to any widget inside a Form widget. The
- problem was that the Form will resize itself when it gets geometry requests
- from its children. If its preferred size is not allowed, the Form will
- disallow all geometry requests from its children. The workaround is that you
- should set any ancestor of the Form to be resizable. For the shell which
- contains the Form you should set the shell resource XmNallowShellResize to be
- True (by default, it is set to FALSE). There is currently an inconsistency on
- how resizing is being done, and it may get fixed in Motif 1.2.
-
- From db@sunbim.be (Danny Backx)
-
- Basically what you have to do is set the XmNresizePolicy on the Form to
- XmRESIZE_NONE. The facts seem to be that XmRESIZE_NONE does NOT mean "do not
- allow resizes". You may also have to set XmNresizable on the form to True.
-
- -----------------------------------------------------------------------------
- Subject: 64) How can I center a widget in a form?
-
- Answer: One of Motif's trickier questions. The problems are that: Form gives
- no support for centering, only for edge attachments, and the widget must stay
- in the center if the form or the widget is resized. Just looking at
- horizontal centering (vertical is similar) some solutions are:
-
- a. Use the table widget instead of Form.
-
- b. A hack free solution is from Dan Heller:
-
- /* Written by Dan Heller. Copyright 1991, O'Reilly && Associates.
- * This program is freely distributable without licensing fees and
- * is provided without guarantee or warranty expressed or implied.
- * This program is -not- in the public domain. This program is
- * taken from the Motif Programming Manual, O'Reilly Volume 6.
- */
-
- /* corners.c -- demonstrate widget layout management for a
- * BulletinBoard widget. There are four widgets each labeled
- * top-left, top-right, bottom-left and bottom-right. Their
- * positions in the bulletin board correspond to their names.
- * Only when the widget is resized does the geometry management
- * kick in and position the children in their correct locations.
- */
- #include <Xm/BulletinB.h>
- #include <Xm/PushBG.h>
-
- char *corners[] = {
- "Top-Left", "Top-Right", "Bottom-Left", "Bottom-Right",
- };
-
- static void resize();
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- Widget toplevel, bboard;
- XtAppContext app;
- XtActionsRec rec;
- int i;
-
- /* Initialize toolkit and create toplevel shell */
- toplevel = XtVaAppInitialize(&app, "Demos", NULL, 0,
- &argc, argv, NULL, NULL);
-
- /* Create your standard BulletinBoard widget */
- bboard = XtVaCreateManagedWidget("bboard",
- xmBulletinBoardWidgetClass, toplevel, NULL);
-
- /* Set up a translation table that captures "Resize" events
- * (also called ConfigureNotify or Configure events). If the
- * event is generated, call the function resize().
- */
- rec.string = "resize";
- rec.proc = resize;
- XtAppAddActions(app, &rec, 1);
- XtOverrideTranslations(bboard,
- XtParseTranslationTable("<Configure>: resize()"));
-
- /* Create children of the dialog -- a PushButton in each corner. */
- for (i = 0; i < XtNumber(corners); i++)
- XtVaCreateManagedWidget(corners[i],
- xmPushButtonGadgetClass, bboard, NULL);
-
- XtRealizeWidget(toplevel);
- XtAppMainLoop(app);
- }
-
- /* resize(), the routine that is automatically called by Xt upon the
- * delivery of a Configure event. This happens whenever the widget
- * gets resized.
- */
- static void
- resize(w, event, args, num_args)
- CompositeWidget w; /* The widget (BulletinBoard) that got resized */
- XConfigureEvent *event; /* The event struct associated with the event */
- String args[]; /* unused */
- int *num_args; /* unused */
- {
- WidgetList children;
- int width = event->width;
- int height = event->height;
- Dimension w_width, w_height;
- short margin_w, margin_h;
-
- /* get handle to BulletinBoard's children and marginal spacing */
- XtVaGetValues(w,
- XmNchildren, &children,
- XmNmarginWidth, &margin_w,
- XmNmarginHeight, &margin_h,
- NULL);
-
- /* place the top left widget */
- XtVaSetValues(children[0],
- XmNx, margin_w,
-
- XmNy, margin_h,
- NULL);
-
- /* top right */
- XtVaGetValues(children[1], XmNwidth, &w_width, NULL);
-
- /* To Center a widget in the middle of the BulletinBoard (or Form),
- * simply call:
- * XtVaSetValues(widget,
- XmNx, (width - w_width)/2,
- XmNy, (height - w_height)/2,
- NULL);
- * and return.
- */
- XtVaSetValues(children[1],
- XmNx, width - margin_w - w_width,
- XmNy, margin_h,
- NULL);
- /* bottom left */
- XtVaGetValues(children[2], XmNheight, &w_height, NULL);
- XtVaSetValues(children[2],
-
- XmNx, margin_w,
- XmNy, height - margin_h - w_height,
- NULL);
- /* bottom right */
- XtVaGetValues(children[3],
- XmNheight, &w_height,
- XmNwidth, &w_width,
- NULL);
- XtVaSetValues(children[3],
- XmNx, width - margin_w - w_width,
- XmNy, height - margin_h - w_height,
- NULL);
- }
-
- c. No uil solution has been suggested, because of the widget size problem
-
- -----------------------------------------------------------------------------
- Subject: 65) How do I line up two columns of widgets of different types? I
- have a column of say label widgets, and a column of text widgets and I want to
- have them lined up horizontally. The problem is that they are of different
- heights. Just putting them in a form or rowcolumn doesn't line them up
- properly because the label and text widgets are of different height.
-
- If you want the geometry to look like this
-
- -------------------------------------
- | -------------------------- |
- |a label |Some text ||
- | -------------------------- |
- ------------------- |
- |a longer label |Some more text ||
- | ------------------- |
- | ---------------- |
- |a very long label |Even more text ||
- | ---------------- |
- -------------------------------------
-
- try
-
- /* Written by Dan Heller. Copyright 1991, O'Reilly && Associates.
- * This program is freely distributable without licensing fees and
- * is provided without guarantee or warranty expressed or implied.
- * This program is -not- in the public domain. This program is
- * taken from the Motif Programming Manual, O'Reilly Volume 6.
- */
-
- /* text_form.c -- demonstrate how attachments work in Form widgets.
- * by creating a text-entry form type application.
- */
-
- #include <Xm/PushB.h>
- #include <Xm/PushBG.h>
- #include <Xm/LabelG.h>
- #include <Xm/Text.h>
- #include <Xm/Form.h>
-
- char *prompts[] = {
- "Name:", "Phone:", "Address:",
- "City:", "State:", "Zip:",
- };
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- Widget toplevel, mainform, subform, label, text;
- XtAppContext app;
- char buf[32];
- int i;
-
- toplevel = XtVaAppInitialize(&app, "Demos", NULL, 0,
- &argc, argv, NULL, NULL);
-
- mainform = XtVaCreateWidget("mainform",
- xmFormWidgetClass, toplevel,
- NULL);
-
- for (i = 0; i < XtNumber(prompts); i++) {
- subform = XtVaCreateWidget("subform",
- xmFormWidgetClass, mainform,
- /* first one should be attached for form */
- XmNtopAttachment, i? XmATTACH_WIDGET : XmATTACH_FORM,
- /* others are attached to the previous subform */
- XmNtopWidget, subform,
- XmNleftAttachment, XmATTACH_FORM,
- XmNrightAttachment, XmATTACH_FORM,
- NULL);
- label = XtVaCreateManagedWidget(prompts[i],
- xmLabelGadgetClass, subform,
- XmNtopAttachment, XmATTACH_FORM,
- XmNbottomAttachment, XmATTACH_FORM,
- XmNleftAttachment, XmATTACH_FORM,
- XmNalignment, XmALIGNMENT_BEGINNING,
- NULL);
- sprintf(buf, "text_%d", i);
- text = XtVaCreateManagedWidget(buf,
- xmTextWidgetClass, subform,
- XmNtopAttachment, XmATTACH_FORM,
- XmNbottomAttachment, XmATTACH_FORM,
- XmNrightAttachment, XmATTACH_FORM,
- XmNleftAttachment, XmATTACH_WIDGET,
- XmNleftWidget, label,
- NULL);
- XtManageChild(subform);
- }
- /* Now that all the forms are added, manage the main form */
- XtManageChild(mainform);
-
- XtRealizeWidget(toplevel);
- XtAppMainLoop(app);
- }
-
- If you resize horizontally it stretches the text widgets. If you resize
- vertically it leaves space under the bottom (if you don't resize, this is not
- problem).
-
- If you want the text widgets to be lined up on the left, as in
-
- ----------------------------------------
- | ------------------- |
- | a label |Some text ||
- | ------------------- |
- ------------------- |
- | a longer label |Some more text ||
- | ------------------- |
- | ------------------- |
- |a very long label |Even more text ||
- | ------------------- |
- ----------------------------------------
-
- try this
-
- /* Written by Dan Heller. Copyright 1991, O'Reilly && Associates.
- * This program is freely distributable without licensing fees and
- * is provided without guarantee or warranty expressed or implied.
- * This program is -not- in the public domain. This program is
- * taken from the Motif Programming Manual, O'Reilly Volume 6.
- */
-
- /* text_entry.c -- This demo shows how the RowColumn widget can be
- * configured to build a text entry form. It displays a table of
- * right-justified Labels and Text widgets that extend to the right
- * edge of the Form.
- */
- #include <Xm/LabelG.h>
- #include <Xm/RowColumn.h>
- #include <Xm/Text.h>
-
- char *text_labels[] = {
- "Name:", "Phone:", "Address:", "City:", "State:", "Zip:",
- };
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- Widget toplevel, rowcol;
- XtAppContext app;
- char buf[8];
- int i;
-
- toplevel = XtVaAppInitialize(&app, "Demos", NULL, 0,
- &argc, argv, NULL, NULL);
-
- rowcol = XtVaCreateWidget("rowcolumn",
- xmRowColumnWidgetClass, toplevel,
- XmNpacking, XmPACK_COLUMN,
- XmNnumColumns, XtNumber(text_labels),
- XmNorientation, XmHORIZONTAL,
- XmNisAligned, True,
- XmNentryAlignment, XmALIGNMENT_END,
- NULL);
-
- /* simply loop thru the strings creating a widget for each one */
- for (i = 0; i < XtNumber(text_labels); i++) {
- XtVaCreateManagedWidget(text_labels[i],
- xmLabelGadgetClass, rowcol,
- NULL);
- sprintf(buf, "text_%d", i);
- XtVaCreateManagedWidget(buf,
- xmTextWidgetClass, rowcol,
- NULL);
- }
-
- XtManageChild(rowcol);
- XtRealizeWidget(toplevel);
- XtAppMainLoop(app);
- }
-
- This makes all objects exactly the same size. It does not resize in nice
- ways.
-
- If you want the text widgets lined up on the left, and the labels to be the
- size of the longest string, resizing nicely both horizontally and vertically,
- as in
-
- -------------------------------------
- | ---------------- |
- | a label |Some text ||
- | ---------------- |
- ---------------- |
- | a longer label |Some more text ||
- | ---------------- |
- | ---------------- |
- |a very long label |Even more text ||
- | ---------------- |
- -------------------------------------
-
-
-
- Answer: Do this: to get the widgets lined up horizontally, use a form but
- place the widgets using XmATTACH_POSITION. In the example, attach the top of
- the first label to the form, the bottomPosition to 33 (33% of the height).
- Attach the topPosition of the second label to 33 and the bottomPosition to 66.
- Attach the topPosition of the third label to 66 and the bottom of the label to
- the form. Do the same with the text widgets.
-
- To get the label widgets lined up vertically, use the right attachment of
- XmATTACH_OPPOSITE_WIDGET: starting from the one with the longest label, attach
- widgets on the right to each other. In the example, attach the 2nd label to
- the third, and the first to the second. To get the text widgets lined up,
- just attach them on the left to the labels. To get the text in the labels
- aligned correctly, use XmALIGNMENT_END for the XmNalignment resource.
-
- /* geometry for label 2
- */
- n = 0;
- XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
- XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
- XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
- XtSetArg (args[n], XmNtopAttachment, XmATTACH_POSITION); n++;
- XtSetArg (args[n], XmNtopPosition, 66); n++;
- XtSetValues (label[2], args, n);
-
- /* geometry for label 1
- */
- n = 0;
- XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
- XtSetArg (args[n], XmNbottomAttachment, XmATTACH_POSITION); n++;
- XtSetArg (args[n], XmNbottomPosition, 66); n++;
- XtSetArg (args[n], XmNtopAttachment, XmATTACH_POSITION); n++;
- XtSetArg (args[n], XmNtopPosition, 33); n++;
- XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
- XtSetArg (args[n], XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
- XtSetArg (args[n], XmNrightWidget, label[2]); n++;
- XtSetValues (label[1], args, n);
-
- /* geometry for label 0
- */
- n = 0;
- XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
- XtSetArg (args[n], XmNbottomAttachment, XmATTACH_POSITION); n++;
- XtSetArg (args[n], XmNbottomPosition, 33); n++;
- XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
- XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
- XtSetArg (args[n], XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
- XtSetArg (args[n], XmNrightWidget, label[1]); n++;
- XtSetValues (label[0], args, n);
-
- /* geometry for text 0
- */
- n = 0;
- XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
- XtSetArg (args[n], XmNbottomAttachment, XmATTACH_POSITION); n++;
- XtSetArg (args[n], XmNbottomPosition, 33); n++;
- XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
- XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
- XtSetArg (args[n], XmNleftWidget, label[0]); n++;
- XtSetValues (text[0], args, n);
-
- /* geometry for text 1
- */
- XtSetArg (args[n], XmNtopAttachment, XmATTACH_POSITION); n++;
- XtSetArg (args[n], XmNtopPosition, 33); n++;
- XtSetArg (args[n], XmNbottomAttachment, XmATTACH_POSITION); n++;
- XtSetArg (args[n], XmNbottomPosition, 66); n++;
- XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
- XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
- XtSetArg (args[n], XmNleftWidget, label[1]); n++;
- XtSetValues (text[1], args, n);
-
- /* geometry for text 2
- */
- XtSetArg (args[n], XmNtopAttachment, XmATTACH_POSITION); n++;
- XtSetArg (args[n], XmNtopPosition, 66); n++;
- XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
- XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
- XtSetArg (args[n], XmNleftWidget, label[2]); n++;
- XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
- XtSetValues (text[2], args, n);
-
-
- -----------------------------------------------------------------------------
- Subject: 66) TOPIC: PUSHBUTTON WIDGET
-
- -----------------------------------------------------------------------------
- Subject: 67) Why can't I use accelerators on buttons not in a menu?
-
- Answer: It is apparently a difficult feature to implement, but OSF are
- considering this for the future. It is problematic trying to use the Xt
- accelerators since the Motif method interferes with this. one workaround
- suggested is to duplicate your non-menu button by a button in a menu
- somewhere, which does have a menu-accelerator installed. When the user
- invokes what they think is the accelerator for the button they can see Motif
- actually invokes the button on the menu that they can't see at the time.
- Another method is described below and was contributed by Harald Albrecht of
- Institute of Geometry and Practical Mathematics Rhine Westphalia Technical
- University Aachen (RWTH Aachen), Germany
-
-
- From albrecht@igpm.rwth-aachen.de Thu Jul 8 11:44:21 1993
-
- My work-around of this problem looks like this: (I've written that code for a
- Motif Object Library in C++ so please forgive me for being object orientated!)
- The hack consists of a rewritten message loop which checks for keypresses
- <MAlt>+<key>. If MessageLoop() finds such a keypress HandleAcc() ist called
- and the widget tree is searched for a suitable widget with the right mnemonic.
-
-
- // --------------------------------------------------------------------------
- // traverse the widget tree starting with the given widget.
- //
- BOOL TraverseWidgetTree(Widget w, char *pMnemonic, XKeyEvent *KeyEvent)
- {
- Widget wChild;
- WidgetList ChildList;
- int NumChilds, Child;
- KeySym LabelMnemonic;
- char *pMnemonicString;
-
- // Check if the widget is a subclass of label -- then it may have an
- // accelerator attached...
- if ( XtIsSubclass(w, xmLabelWidgetClass) ) {
- // ok. Now: get the widget's mnemonic, convert it to ASCII and compare
- // it with the Key we're looking for.
- XtVaGetValues(w, XmNmnemonic, &LabelMnemonic, NULL);
- pMnemonicString = XKeysymToString(LabelMnemonic);
- if ( pMnemonicString &&
- (strcasecmp(pMnemonicString, pMnemonic) == 0) ) {
- // stimulate the keypress
- XmProcessTraversal((Widget)w, XmTRAVERSE_CURRENT);
- KeyEvent->type = KeyPress;
- KeyEvent->window = XtWindow(w);
- KeyEvent->subwindow = XtWindow(w);
- KeyEvent->state = 0;
- KeyEvent->keycode =
- XKeysymToKeycode(XtDisplay(w), XK_space);
- XSendEvent(XtDisplay(w), XtWindow(w),
- True,
- ButtonPressMask, (XEvent*) KeyEvent);
- KeyEvent->type = KeyRelease;
- XSendEvent(XtDisplay(w), XtWindow(w),
- True,
- ButtonReleaseMask, (XEvent*) KeyEvent);
- return True;
- }
- }
- // if this widget is a subclass of Composite check all the widget's
- // childs.
- if ( XtIsSubclass(w, compositeWidgetClass) ) {
- // if we're in a menu (or something like that) forget this leaf of the
- // widget tree!
- if ( XtIsSubclass(w, xmRowColumnWidgetClass) ) {
- unsigned char RowColumnType;
- XtVaGetValues(w, XmNrowColumnType, &RowColumnType, NULL);
- if ( RowColumnType != XmWORK_AREA ) return False;
- }
- XtVaGetValues(w, XmNchildren, &ChildList,
- XmNnumChildren, &NumChilds, NULL);
- for ( Child = 0; Child < NumChilds; ++Child ) {
- wChild = ChildList[Child];
- if ( TraverseWidgetTree(wChild, pMnemonic, KeyEvent) )
- return True;
- }
- }
- return False;
- } // TraverseWidgetTree
- // --------------------------------------------------------------------------
- // handle accelerators (keypress MAlt + key)
- //
- #define MAX_MAPPING 10
- BOOL HandleAcc(Widget w, XEvent *event)
- {
- Widget widget, OldWidget;
- static char keybuffer[MAX_MAPPING];
- int CharCount;
- static XComposeStatus composeStatus;
-
- // convert KeyPress to ASCII
- CharCount = XLookupString((XKeyEvent*) event,
- keybuffer, sizeof(keybuffer),
- NULL, &composeStatus);
- keybuffer[CharCount] = 0;
- // Only one char is alright -- then search the widget tree for a widget
- // with the right mnemonic
- if ( CharCount == 1 ) {
- keybuffer[0] = tolower(keybuffer[0]);
- widget = w;
- while ( (widget != NULL) &&
- !XtIsSubclass(widget, shellWidgetClass) ) {
- OldWidget = widget; widget = XtParent(widget);
- }
- if ( !widget ) widget = OldWidget;
- return TraverseWidgetTree(widget,
- keybuffer, (XKeyEvent*) event);
- }
- return False; // no-one found.
- } // HandleAcc
- // --------------------------------------------------------------------------
- // modified message loop
- // loops until the Boolean pFlag points to is set to False
- void MessageLoop(Boolean *pFlag)
- {
- XEvent nextEvent;
-
- while ( *pFlag ) {
- if ( XtAppPending(AppContext) ) {
- XtAppNextEvent(AppContext, &nextEvent);
- if ( nextEvent.type == KeyPress ) {
- // Falls es ein Tastendruck ist, bei dem auch noch die ALT-Taste
- // (=Modifier 1) gedrueckt ist, koennte es ein Accelerator sein!
- if ( nextEvent.xkey.state & Mod1Mask )
- if ( HandleAcc(XtWindowToWidget(nextEvent.xkey.display,
- nextEvent.xkey.window),
- &nextEvent) )
- continue; // Mitteilung konnte ausgeliefert werden
- // und darf daher nicht den ueblichen
- // Weg gehen!
- }
- XtDispatchEvent(&nextEvent);
- }
- }
- } // TApplication::MessageLoop
-
-
- Harald Albrecht albrecht@igpm.rwth-aachen.de Institute of Geometry and
- Practical Mathematics Rhine Westphalia Technical University Aachen (RWTH
- Aachen), Germany
-
-
- -----------------------------------------------------------------------------
- Subject: 68) TOPIC: LABEL WIDGET
-
- -----------------------------------------------------------------------------
- Subject: 69) How can I align the text in a label (button, etc) widget?
-
- Answer: The alignment for the label widget is controlled by the resource
- XmNalignment, and the default centers the text. Use this resource to change it
- to left or right alignment. However, when the label (or any descendant) is in
- a row column, and XmNisAligned is True (the default), the row column aligns
- text using its resource XmNentryAlignment. If you want simultaneous control
- over all widgets use this, but otherwise turn XmNisAligned off and do it
- individually.
-
-
-
- -----------------------------------------------------------------------------
- Subject: 70) Why doesn't label alignment work in a RowColumn?
-
- Answer: RowColumn has a resource XmNisAligned (default True) and and
- XmNentryAlignment (default XmALIGNMENT_BEGINNING). These control alignment of
- the labelString in Labels and descendants. Set XmNisAligned to False to turn
- this off.
-
- -----------------------------------------------------------------------------
- Subject: 71) How can I set a multiline label?
- [Last modified: September 92]
-
- Answer: In .Xdefaults
-
- *XmLabel*labelString: Here\nis\nthe\nLabel
-
- This method does not seem to work in some of the older Motif 1.0 versions.
-
- In code,
-
- char buf[128];
- XmString msg;
- sprintf(buf, "Here\nis\nthe\nLabel");
- msg = XmStringCreateLtoR(buf, XmSTRING_DEFAULT_CHARSET);
- XtSetArg (args[n], XmNlabelString, msg);
-
- Gives a four line label, using the escape sequence \n for a newline. However,
- XmStringCreateLtoR() is obsoleted from version 1.1 on, and may disappear.
- This is because it it is only in the AES as "trial-use" and has been proposed
- for removal from the AES. Realistically, it will probably not be removed from
- any backward compatible versions of Motif, but the potential is there. If it
- does disappear (or if you want to avoid using the non-AES compliant
- XmSTRING_DEFAULT_CHARSET), try this from Jean-Philippe Martin-Flatin
- <syj@ecmwf.co.uk>
-
- #include <Xm/Xm.h>
- #include <string.h>
-
- /*-----------------------------------------------------
- Create a new XmString from a char*
-
- This function can deal with embedded 'newline' and
- is equivalent to the obsolete XmStringCreateLtoR,
- except it does not use non AES compliant charset
- XmSTRING_DEFAULT_CHARSET
- ----------------------------------------------------*/
- XmString xec_NewString(char *s)
- {
- XmString xms1;
- XmString xms2;
- XmString line;
- XmString separator;
- char *p;
- char *t = XtNewString(s); /* Make a copy for strtok not to */
- /* damage the original string */
-
-
- separator = XmStringSeparatorCreate();
- p = strtok(t,"\n");
- xms1 = XmStringCreateSimple(p);
-
- while (p = strtok(NULL,"\n"))
- {
- line = XmStringCreateSimple(p);
- xms2 = XmStringConcat(xms1,separator);
- XmStringFree(xms1);
- xms1 = XmStringConcat(xms2,line);
- XmStringFree(xms2);
- XmStringFree(line);
- }
-
- XmStringFree(separator);
- XtFree(t);
- return xms1;
- }
-
-
- Do not use XmStringCreateSimple() - it does not process the newline character
- in the way you want.
-
- In UIL, you have to explicitly create a compound string with a separator.
- Here's what W. Scott Meeks suggests:
-
- value nl : compound_string('', seperate=true);
-
- object my_label : XmLabel
- {
- arguments
- {
- XmNlabelString = 'Here' & nl & 'is' & nl & 'the' & nl & 'Label';
- };
- };
-
-
- -----------------------------------------------------------------------------
- Subject: 72) How can I have a vertical label?
-
- Answer: Make a multiline label with one character per line, as in the last
- question. There is no way to make the text rotated by 90 degrees though.
-
-
- -----------------------------------------------------------------------------
- Subject: 73) How can I have a Pixmap in a Label?
-
- Answer: From Bob Hays (bobhays@spss.com)
-
- Pixmap px_disarm, px_disarm_insens;
-
- Widget Label1;
- Pixel foreground, background;
- Arg args[4];
- Arg arg[] = {
- { XmNforeground, &foreground },
- { XmNbackground, &background }
- };
-
- Label1 = XmCreateLabel ( Shell1, "Label1",
- (Arg *) NULL, (Cardinal) 0 );
- XtGetValues ( Label1, arg, XtNumber ( arg ) );
- px_disarm =
- XCreatePixmapFromBitmapData(display,
- DefaultRootWindow(display),
- mtn_bits, mtn_width, mtn_height,
- foreground,
- background,
- DefaultDepth(display,DefaultScreen(display)));
- px_disarm_insens =
- XCreatePixmapFromBitmapData(display,
- DefaultRootWindow(display),
- mtn_ins_bits, mtn_ins_width, mtn_ins_height,
- foreground,
- background,
- DefaultDepth(display,DefaultScreen(display)));
-
- n = 0;
- XtSetArg(args[n], XmNlabelType, XmPIXMAP); n++;
- XtSetArg(args[n], XmNlabelPixmap, px_disarm); n++;
- XtSetArg(args[n], XmNlabelInsensitivePixmap, px_disarm_insens ); n++;
- XtSetValues ( Label1, args, n );
- XtManageChild(Label1);
-
- That will cause the foreground and background of your pixmap to be inherited
- from the one that would be used by OSF/Motif when the label is displayed. The
- advantage is that this will utilize any resource values the user may have
- requested without looking explicitly into the resource database. And, you
- will have a pixmap handy if the application insensitizes the label (without an
- XmNlabelInsensitivePixmap your label will go empty if made insensitive).
-
- [Bob's original code was for a PushButton. Just change all Label to PushButton
- for them.]
-
-
- -----------------------------------------------------------------------------
- Subject: 74) TOPIC: DRAWING AREA WIDGET
-
- -----------------------------------------------------------------------------
- Subject: 75) How can I send an expose event to a Drawing Area widget? (or
- any other, come to that). I want to send an expose event so that it will
- redraw itself.
-
- Answer: Use the Xlib call
-
- XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, True)
-
- This clears the widget's window and generates an expose event in doing so.
- The widgets expose action will then redraw it. This uses a round trip
- request. An alternative, without the round trip is
-
- from orca!mesa!rthomson@uunet.uu.net (Rich Thomson):
-
- Widget da;
- XmDrawingAreaCallbackStruct da_struct;
-
- da_struct.reason = XmCR_EXPOSE;
- da_struct.event = (XEvent *) NULL;
- da_struct.window = XtWindow(da);
-
- XtCallCallbacks(da, XmNexposeCallback, (XtPointer) da_struct);
-
-
- -----------------------------------------------------------------------------
- Subject: 76) How can I know when a DrawingArea has been resized? It
- generates an expose event whn it is enlarged, but not when it is shrunk.
-
- Answer: Use the resize callback.
-
- -----------------------------------------------------------------------------
- Subject: 77) TOPIC: MENUS
-
- -----------------------------------------------------------------------------
- Subject: 78) What can I put inside a menu bar?
-
- Answer: You can only put cascade buttons in menu bars. No pushbuttons, toggle
- buttons or gadgets are allowed. When you create a pulldown menu with parent a
- menu bar, its real parent is a shell widget.
-
- -----------------------------------------------------------------------------
- Subject: 79) Can I have a cascade button without a submenu in a pulldown
- menu?
-
- Answer: Yes you can. A cascade button has an activate callback which is called
- when you click on it and it doesn't have a submenu. It can have a mnemonic,
- but keyboard traversal using the arrow keys in the menu will skip over it.
-
- -----------------------------------------------------------------------------
- Subject: 80) Should I have a cascade button without a submenu in a pulldown
- menu?
-
- Answer: No. This is forbidden by the style guide. Technically you can do it
- (see previous question) but if you do it will not be Motif style compliant.
- This is unlikely to change - if a "button" is important enough to be in a
- pulldown menu bar with no pulldown, it should be a button elsewhere. (Mind
- you, you won't be able to put accelerators on it elsewhere though.)
-
- -----------------------------------------------------------------------------
- Subject: 81) What is the best way to create popup menus?
- [Last modified: August 92]
-
- Susan Murdock Thompson (from OSF): In general, create a popupMenu as the child
- from which you will be posting it from (ie: if you have a bulletinBoard with a
- PushButton in it and want MB2 on the pushButton to post the popupMenu, create
- the popupMenu as a child of the pushButton). [This parent-child relationship
- seems to make a big difference in the behavior of the popups.] Add an event
- handler to handle buttonPress events. You'll need to check for the correct
- button (what you've specified menuPost to be) before posting the menu.
-
- To create a popup that can be accessible from within an entire client window,
- create it as the child of the top-most widget (but not the shell) and add
- event handlers for the top-most widget and children widgets.
-
- ie:
-
- {
- ....
-
- XtManageChild(rc=XmCreateRowColumn(Shell1, "rc", NULL, 0));
- XtManageChild(label = XmCreateLabel(rc, "label", NULL, 0));
- XtManageChild(text = XmCreateText(rc, "text", NULL, 0));
- XtManageChild(pushbutton = XmCreatePushButton(rc, "pushbutton", NULL, 0));
-
- n = 0;
- XtSetArg(args[n], XmNmenuPost, "<Btn3Down>"); n++;
- popup = XmCreatePopupMenu(rc, "popup", args, n);
-
- XtAddEventHandler(rc, ButtonPressMask, False, PostMenu3, popup);
- XtAddEventHandler(text, ButtonPressMask, False, PostMenu3, popup);
- XtAddEventHandler(label, ButtonPressMask, False, PostMenu3, popup);
- XtAddEventHandler(pushbutton, ButtonPressMask, False, PostMenu3, popup);
-
- XtManageChild(m1 = XmCreatePushButton(popup, "m1", NULL, 0));
- XtManageChild(m2 = XmCreatePushButton(popup, "m2", NULL, 0));
- XtManageChild(m3 = XmCreatePushButton(popup, "m3", NULL, 0));
-
- XtAddCallback(m1, XmNactivateCallback, SayCB, "button M1");
- XtAddCallback(m2, XmNactivateCallback, SayCB, "button M2");
- XtAddCallback(m3, XmNactivateCallback, SayCB, "button M3");
- ...
- }
-
- /* where PostMenu3 is ... */
-
- PostMenu3 (w, popup, event)
- Widget w;
- Widget popup;
- XButtonEvent * event;
- {
- printf("menuPost = 3, button %d0, event->button);
-
- if (event->button != Button3)
- return;
- XmMenuPosition(popup, event);
- XtManageChild(popup);
- }
-
-
-
- -----------------------------------------------------------------------------
- Subject: 82) How do popup menus work?
- [Last modified: August 92]
-
- Answer:
-
- When a popup menu is created as the child of a widget the menu system installs
- a translation on the parent of the popup and descendants with an action which:
- (1) when 3-rd button (the default for the menuPost resource) is pressed the
- cursor changes and the mouse is grabbed for 5 seconds; (2) disables event
- handlers on the descendants and the handlers are never called; (3) an event
- handler installed on the parent works fine.
-
- It is done so that the correct event handler will (in fact) be called. There
- is a grab with owner_events true. The grab is released by a timer, but
- normally the posted menu shell puts up it's own grab.
-
- If you only have widgets then you can use the subwindow field in the event to
- identify the original widget. If you have gadgets or other data that you want
- to change the menu for (or use a specific menu for) then you must do a walk of
- the parent's children to find the best match.
-
- One thing to beware of is that even with the grab, because the menu system
- does a grab with owner events true, you must either have an event handler, or
- nothing that will use the event on each widget in the hierarchy of the menu's
- parent. If a child widget has another event handler for button down, it may
- swallow the event and do something else.
-
-
-
- -----------------------------------------------------------------------------
- Subject: 83) Should I use translation tables or actions for popup menus?
- [Last modified: August 92]
-
- Answer: The original goal of popupMenus was that the user would not have to
- specify an event handler to manage popupMenus; however, that did not become
- reality. Larry Rogers wrote:
-
- > There appear to be two ways to manage popup menus. I
- > am curious what the correct way would be:
-
- > 1. Change the translation table of the widget with the
- > popup child to popup the menu. Note that this does
- > not currently working for many widgets, because aug-
- > menting their translations, even for augment breaks
- > the widget.
-
- > 2. Add an event handler at creation to the widget; then
- > determine if the event that caused the event handler
- > to be called is the current button being used by the
- > menu as its activation button.
-
- Susan Murdock Thompson (from OSF) replied: *Theoretically, you should be able
- to do both.* Our documentation says use event handlers. Our tests for the
- toolkit use event handlers and for UIL use translations. (Although I tried an
- event handler with a UIL test and it works).
-
- -----------------------------------------------------------------------------
- Subject: 84) What are the known bugs in popup menus?
- [Last modified: August 92]
-
- Answer: As at Motif 1.1.4, the bugs for which an OSF PIR exists are:
-
- (3) Menus not being sticky (ie: posted on a Btn CLICK) [ Note:this
- problem occurs with OptionMenus as well] (PIR 3435)
-
- (6) Destroying a widget with an associated popupMenu results in
- "Warning: Attempt to remove non-existant passive grab" (PIR
- 2972)
-
- (7) Current documentation insufficient regarding requirements for
- success in using PopupMenus. (PIR 3433)
-
-
- -----------------------------------------------------------------------------
- Subject: 85) Can I have multiple popup menus on the same widget?
- [Last modified: August 92]
-
- Answer: If you want to have several popups (activated by different mouse
- buttons) on the same widget..., well, that doesn't work yet.
-
- If you want to have several popups on different children... that works. But
- don't put a popup on the parent (manager) widget, or it will rule!
-
-
-
- -----------------------------------------------------------------------------
- Subject: 86) TOPIC: INPUT FOCUS
-
- -----------------------------------------------------------------------------
- Subject: 87) How can I specify the widget that should have the keyboard focus
- when my application starts up? Answer: In Motif 1.2, use XmNinitialFocus on
- the manager widget. thanks to Ken Lee, klee@synoptics.com
-
-
- -----------------------------------------------------------------------------
- Subject: 88) How can I direct the keyboard input to a particular widget?
-
- Answer: In Motif 1.1 call XmProcessTraversal(target, XmTRAVERSE_CURRENT). The
- widget (and all of its ancestors) does need to be realized BEFORE you call
- this. Otherwise it has no effect. XmProcessTraversal is reported to have many
- bugs, so it may not work right. A common occurrence is that it doesn't move
- to the widget, but if you call XmProcessTraversal *twice* in a row, it will.
- If you can't get it to work, try this from Kee Hinckley:
-
- // This insane sequence is as follows:
- // On manage set up a focus callback
- // On focus callback set up a timer (and get rid of focus callback!)
- // On timer set the focus (which only works if the parent
- // has the focus,
- // which is why we went through all of this garbage)
- // There may be a better way, but I haven't time to try it now.
- //
- static void focusTO(void *data, XtIntervalId *) {
- XmProcessTraversal((Widget) data, XmTRAVERSE_CURRENT);
- }
-
- static void focusCB(Widget w, XtPointer data, XtPointer) {
- XtRemoveCallback(w, XmNfocusCallback, focusCB, data);
- XtAppAddTimeOut(XtWidgetToApplicationContext(w), 0, focusTO, data);
- }
-
- void OmXSetFocus(Widget parent, Widget w) {
- XtAddCallback(parent, XmNfocusCallback, focusCB, w);
- }
-
-
- In Motif 1.0 call the undocumented _XmGrabTheFocus(target).
-
- Do not use the X or Xt calls such as XtSetKeyboardFocus since this bypasses
- the Motif traversal layer and can cause it to get confused. This can lead to
- odd keyboard behaviour elsewhere in your application.
-
- -----------------------------------------------------------------------------
- Subject: 89) How can I have a modal dialog which has to be answered before
- the application can continue?
- [Last modified: July 92]
-
- Answer: The answer depends on whether you are using the Motif window manager
- mwm or not. Test for this by XmIsMotifWMRunning.
-
- The window manager mwm knows how to control event passing to dialog widgets
- declared as modal. If the dialog is set to application modal, then no
- interaction with the rest of the application can occur until the dialog is
- destroyed or unmanaged.
-
- Use the appropriate code in the following program. There is followup
- discussion after the program.
-
-
- /* Written by Dan Heller. Copyright 1991, O'Reilly && Associates.
- * This program is freely distributable without licensing fees and
- * is provided without guarantee or warranty expressed or implied.
- * This program is -not- in the public domain. This program is
- * taken from the Motif Programming Manual, O'Reilly Volume 6.
- */
-
- /*
- * ask_user.c -- create a pushbutton that posts a dialog box
- * that asks the user a question that requires an immediate
- * response. The function that asks the question actually
- * posts the dialog that displays the question, waits for and
- * returns the result.
- */
- #include <X11/Intrinsic.h>
- #include <Xm/DialogS.h>
- #include <Xm/SelectioB.h>
- #include <Xm/RowColumn.h>
- #include <Xm/MessageB.h>
- #include <Xm/PushBG.h>
- #include <Xm/PushB.h>
-
- XtAppContext app;
-
- #define YES 1
- #define NO 2
-
- /* main() --create a pushbutton whose callback pops up a dialog box */
- main(argc, argv)
- char *argv[];
- int argc;
- {
- Widget parent, button, toplevel;
- XmString label;
- void pushed();
-
- toplevel = XtAppInitialize(&app, "Demos",
- NULL, 0, &argc, argv, NULL, NULL, 0);
-
- label = XmStringCreateSimple("/bin/rm *");
- button = XtVaCreateManagedWidget("button",
- xmPushButtonWidgetClass, toplevel,
- XmNlabelString, label,
- NULL);
- XtAddCallback(button, XmNactivateCallback,
- pushed, "Remove Everything?");
- XmStringFree(label);
-
- XtRealizeWidget(toplevel);
- XtAppMainLoop(app);
- }
-
- /* pushed() --the callback routine for the main app's pushbutton. */
- void
- pushed(w, question)
- Widget w;
- char *question;
- {
- if (AskUser(w, question) == YES)
- puts("Yes");
- else
- puts("No");
- }
-
- /*
- * AskUser() -- a generalized routine that asks the user a question
- * and returns the response.
- */
- AskUser(parent, question)
- char *question;
- {
- static Widget dialog;
- XmString text, yes, no;
- static int answer;
- extern void response();
-
- answer = 0;
- if (!dialog) {
- dialog = XmCreateQuestionDialog(parent, "dialog", NULL, 0);
- yes = XmStringCreateSimple("Yes");
- no = XmStringCreateSimple("No");
- XtVaSetValues(dialog,
- XmNdialogStyle, XmDIALOG_APPLICATION_MODAL,
- XmNokLabelString, yes,
- XmNcancelLabelString, no,
- NULL);
- XtSetSensitive(
- XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON), False);
- XtAddCallback(dialog, XmNokCallback, response, &answer);
- XtAddCallback(dialog, XmNcancelCallback, response, &answer);
- /* if the user interacts via the system menu: */
- XtAddCallback(dialog, XmNpopdownCallback, response, &answer);
- }
- text = XmStringCreateSimple(question);
- XtVaSetValues(dialog,
- XmNmessageString, text,
- NULL);
- XmStringFree(text);
- XtManageChild(dialog);
- XtPopup(XtParent(dialog), XtGrabNone);
-
- /* while the user hasn't provided an answer, simulate XtMainLoop.
- * The answer changes as soon as the user selects one of the
- * buttons and the callback routine changes its value. Don't
- * break loop until XtPending() also returns False to assure
- * widget destruction.
- */
- while (answer == 0 || XtAppPending(app))
- XtAppProcessEvent(app, XtIMAll);
- return answer;
- }
-
- /* response() --The user made some sort of response to the
- * question posed in AskUser(). Set the answer (client_data)
- * accordingly and destroy the dialog.
- */
- void
- response(w, answer, reason)
- Widget w;
- int *answer;
- XmAnyCallbackStruct *reason;
- {
- switch (reason->reason) {
- case XmCR_OK:
- *answer = YES;
- break;
- case XmCR_CANCEL:
- *answer = NO;
- break;
- default:
- *answer = NO;
- return;
- }
- }
-
-
-
- If you aren't running a window manager that acknowledges this hint, then you
- may have to grab the pointer (and keyboard) yourself to make sure the user
- doesn't interact with any other widget. Change the grab flag in XtPopup to
- XtGrabExclusive, and XtRemoveGrab(XtParent(w)) to the response() function.
-
-
- -----------------------------------------------------------------------------
- Subject: 90) TOPIC: MEMORY AND SPEED
-
- -----------------------------------------------------------------------------
- Subject: 91) When can I free data structures passed to or retrieved from
- Motif?
-
- Answer:
- In most cases, especially for XmStrings and XmFontLists, Motif copies data
- passed to it or retrieved from it, so it may be freed immediately. Server-
- side resources, such as pixmaps and color cells, however, are not copied, so
- should not be freed. More recent versions of Motif are better than earlier
- versions and exceptions should be documented. thanks to klee*synoptics.com
- (Ken Lee)
-
- -----------------------------------------------------------------------------
- Subject: 92) Why does my application grow in size?
-
- Answer: Motif 1.0 has many memory leaks, particularly in XmString
- manipulation. Switch to Motif 1.1.
-
- Answer: The Intrinsics have a memory leak in accelerator table management, and
- Motif uses this heavily. Avoid this by mapping/unmapping widgets rather than
- creating/destroying them, or get X11R4 fix-15/16/17.
-
- Answer: The server may grow in size due to its own memory leaks. Switch to a
- later server.
-
- Answer: You are responsible for garbage collection in `C'. Some common cases
- where a piece of memory becomes garbage are
-
- a. Memory is allocated by Motif for XmStrings by the functions
- XmStringConcat, XmStringCopy, XmStringCreate, XmStringCreateLtoR,
- XmStringCreateSimple, XmStringDirectionCreate, XmStringNConcat,
- XmStringNCopy, XmStringSegmentCreate, and XmStringSeparatorCreate. The
- values returned by these functions should be freed using XmStringFree
- when they are no longer needed.
-
- b. Memory is allocated by Motif for ordinary character strings (of type
- String) by Motif in XmStringGetLtoR, XmStringGetNextComponent, and
- XmStringGetNextSegment. After using the string, XtFree() it. [Note that
- XmStrings and Strings are two different data types. XmStrings are
- XmStringFree'd, Strings are XtFree'd.]
-
- c. If you have set the label (an XmString) in a label, pushbutton, etc
- widget, free it after calling XtSetValues() or the widget creation
- routine by XmStringFree().
-
- d. If you have set text in a text widget, the text widget makes its own
- copy. Unless you have a use for it, there is no need to keep your own
- copy.
-
- e. If you have set the strings in a list widget the list widget makes its
- own copy. Unless you have a use for it, there is no need to keep your
- own copy.
-
- f. When you get the value of a single compound string from a Widget e.g.
- XmNlabelString, XmNmessageString, ... Motif gives you a copy of its
- internal value. You should XmStringFree this when you have finished with
- it.
-
- g. On the other hand, when you get a value of a Table e.g. XmStringTable for
- a List, you get a *pointer* to the internal Table, and should not free
- it.
-
- h. When you get the value of the text in a widget by XmTextGetString or from
- the resource XmNvalue, you get a copy of the text. You should XtFree
- this when you have finished with it.
-
- Answer: From Josef Nelissen: at least in Motif 1.1.4, X11R4 on a HP 720, the
- XmText/XmTextFieldSetString() functions have a memory leak. The old
- value/contents of the Widget isn't freed correctly. To work around this bug,
- one should use a XmText Widget (in single-line-mode) instead of a XmTextField
- Widget (the solution fails with XmTextField Widgets !) and replace any
-
- XmTextSetString(text_widget, str);
-
- by
-
- XmTextReplace(text_widget, (XmTextPosition) 0,
- XmTextGetLastPosition(text_widget), str);
-
-
- -----------------------------------------------------------------------------
- Subject: 93) Why does my application take a long time to start up?
-
- Answer: You are probably creating too many widgets at startup time. Delay
- creating them until needed. If you have a large number of resources in text
- files (such as in app-defaults), time may be spent reading and parsing it.
-
- -----------------------------------------------------------------------------
- Subject: 94) My application is running too slowly. How can I speed it up?
-
- Answer: Use the R4 rather than R3 server. It is much faster.
-
- Answer: The standard memory allocator is not well tuned to Motif, and can
- degrade performance. Use a better allocator. e.g. with SCO Unix, link with
- libmalloc.a; use the allocator from GNU emacs; use the allocator from Perl.
-
- Answer: Avoid lots of widget creation and destruction. It fragments memory
- and slows everything down. Popup/popdown, manage/unmanage instead.
-
- Answer: Set mappedWhenManaged to FALSE, and then call XtMapWidget()
- XtUnmapWidget() rather than managing.
-
- Answer: Get more memory - your application, the server and the Operating
- System may be spending a lot of time being swapped.
-
- Answer: If you are doing much XmString work yourself, such as heavy use of
- XmStringCompare, speed may deteriorate due to the large amount of internal
- conversions and malloc'ing. Try using XmStringByteCompare if appropriate or
- ordinary Ascii strings if you can.
-
-
-
- -----------------------------------------------------------------------------
- Subject: 95) Why is my application so huge?
-
- Answer: The typical size of a statically linked Motif app is in the megabytes.
- This is often caused by the size of libXm.a. A large part of this gets linked
- in to even trivial Motif programs. You can reduce the code size by linking
- against shared libraries if they are available. Running "strip" on the
- executable can often reduce size. Note that the size of the running program
- should be measured by "ps", not by the code size.
-
- -----------------------------------------------------------------------------
- END OF PART THREE
- --
- ..........................
-
-